package environment.player;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.ShapeGraphicAttribute;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

import environment.Pitch;
import environment.Team;

import ain.*;

import util.CustomFormatter;
import util.Vector;

abstract class AbstractPlayer implements Player
{	
	protected Vector position, velocity; // vectors indicating the position on the pitch and the current velocity
	protected Team team; // the team the player is a poart of: eigher HOME or AWAY
	protected Vector homeGoal, opponentGoal; // vector to the middle point on the line of the goal of the HOME/AWAY team
	protected ImmuneNetwork immuneNetwork; // the immune network used to chose actions
	protected Pitch pitch; // reference to the pitch to get location of the ball etc
	protected long lastKickStartingTime;
	protected ArrayList<Antibody> antibodies; // list of possible actions/antibodies to chose from
	protected Antibody action; // the action that is currently executed/chosen
	protected int ID; // the ID of the player
	protected double AINupdateFreq; // max frequency of AIN updates in ms
	protected long timeOfLastAINUpdate; // time of the last AIN update
	
	protected static int ID_COUNTER  = 0;
	protected static double SIZE = 20;
	protected static double MAX_SPEED = 1;
	protected static double KICKING_RANGE = 3;
	protected static double KICK_DURATION = 500; // time in ms
	public static double MAX_KICK_IMPULSE = 6;
	
	public AbstractPlayer(Pitch pitch, Vector position, Team team)
	{
		// starting position and velocity
		this.position = position;
		velocity = new Vector();
		
		// team and opponent information
		this.team = team;
		homeGoal = team.equals(Team.HOME) ? new Vector(pitch.getWidth(), pitch.getHeight()/2) : new Vector(0, pitch.getHeight()/2);
		opponentGoal = team.equals(Team.AWAY) ? new Vector(pitch.getWidth(), pitch.getHeight()/2) : new Vector(0, pitch.getHeight()/2);
		
		this.pitch = pitch;
		
		lastKickStartingTime = 0;
		
		antibodies = new ArrayList<Antibody>();
		
		ID = ID_COUNTER++;
		
		AINupdateFreq = 0;
	}
	
	public abstract void addImmuneNetwork();
	
	public void update()
	{
		// player decides what to do next
		// the immune network is just updated every other iteration
		long now = System.currentTimeMillis();
		if (now - timeOfLastAINUpdate > AINupdateFreq)
		{
			immuneNetwork.update();
			timeOfLastAINUpdate = now;
			
			// find antibody with highest concentration
			double maxConcentration = Double.NEGATIVE_INFINITY;		
			for (Antibody a : antibodies)
			{					
				if (a.getConcentration() >= maxConcentration)
				{
					maxConcentration = a.getConcentration();
					action = a;
				}
			}
		}
		
//		action.execute();
	}
	
	public abstract void kick(Vector impulse);
	
	public abstract void walk(Vector target);
	
	public void reset()
	{
		lastKickStartingTime = 0;
//		addImmuneNetwork();
	}
	
	public Vector getPosition()
	{
		return position.clone();
	}
	
	public void setPosition(Vector position)
	{
		this.position = position.clone();
	}
	
	public Team getTeam()
	{
		return team;
	}
	
	public Vector getHomeGoal()
	{
		return homeGoal.clone();
	}
	
	public Vector getOpponentGoal()
	{
		return opponentGoal.clone();
	}
	
	public int getID()
	{
		return ID;
	}
	
	public double getMaxKickImpulse()
	{
		return MAX_KICK_IMPULSE;
	}
	
	public ImmuneNetwork getImmuneNetwork()
	{
		return immuneNetwork;
	}
	
	public void draw(Graphics2D g2)
	{
		// prepare drawing the player
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
		RenderingHints.VALUE_ANTIALIAS_ON);
		if (team.equals(Team.HOME)) g2.setColor(Color.RED);
		else g2.setColor(Color.BLUE);
		
		// draw player as a circle
		Ellipse2D.Double circle = new Ellipse2D.Double(position.getX() - SIZE/2,
				position.getY() - SIZE/2,
				SIZE,
				SIZE);
		g2.fill(circle);
		g2.draw(circle);
		
		// draw FAR_RADIUS (= 88) around player
//		double FAR_RADIUS = pitch.getWidth()/4;
//		Ellipse2D.Double farRadius = new Ellipse2D.Double(position.getX() - FAR_RADIUS,
//					position.getY() - FAR_RADIUS,
//					2 * FAR_RADIUS, 2 * FAR_RADIUS);
//		g2.draw(farRadius);
		
		// draw player as a number
//		g2.setColor(Color.BLACK);
//		g2.setFont(new Font("Dialog", Font.PLAIN, 20));
//		g2.drawString(String.valueOf(ID), (float) position.getX() - 5, (float) position.getY() + 5);
		
		// draw chosen action
		g2.setColor(Color.BLACK);
		g2.setFont(new Font("Dialog", Font.PLAIN, 9));
		g2.drawString(action.toString(), (float) position.getX(), (float) (position.getY() - SIZE/2));
		
		// draw concentrations
		NumberFormat f = NumberFormat.getInstance();
		f.setMinimumFractionDigits(2);
		g2.setColor(Color.BLACK);
		g2.setFont(new Font("Dialog", Font.PLAIN, 9));
		for (Antibody a : immuneNetwork.getAntibodies())
		{
			String str = a.toString() + ":\t" + f.format(a.getAntigenAffinity()) 
					+ " " + f.format(a.getConcentration());
			g2.drawString(str, (float) (position.getX() + SIZE/2),
					(float) (position.getY() - SIZE/2 + 9 + a.getID() * 9));
		}
	}
	
	public String toString()
	{
		return team.toString();
	}
}
